using FineCollection.Intf;




namespace FineCollection.Immutable
{
    /// <summary>
    /// Immutable set. 
    /// All items are different, nulls are not allowed.
    /// </summary>
    /// <typeparam name="T">type of an item.</typeparam>
    public class ImmList<T> : ImmArray<T>, RRandomList<T> 
        where T: System.IEquatable<T>
    {
        #region CONSTRUCTORS

        /// <summary>
        /// Makes an immutable set with 2 items.
        /// </summary>
        /// <param name="firstIndex">the origin index.</param>
        /// <param name="items">items, can be null or an empty array.</param>
        /// <remarks>
        /// Given items must be different and not null.
        /// </remarks>
        public ImmList(int firstIndex, params T[] items) 
            : base(firstIndex, items, arrSize(items), false)
        {}

        private static int arrSize(T[] array)
        {
            return array != null ? array.Length : 0;
        }

        #endregion



        /*
        /// <summary>
        /// Checks whether the specified item presents in this collection.
        /// </summary>
        /// <param name="item">items to check for presence.</param>
        /// <remarks>
        /// The complexity of this function is <i>o(n)</i>.
        /// </remarks>
        public bool Contains(T item)
        {
            for (int i = 0; i < count; i++)
                if (arr[i].Equals(item))
                    return true;
            return false;
        }
        */



        /// <summary>
        /// The first item.
        /// Raises an exception when the collection is empty.
        /// </summary>
        /// <exception cref="CollectionIsEmpty">when the collection is empty.</exception>
        public T First
        {
            get
            {
                if (count >= 1)
                    return arr[0];
                else
                    throw new CollectionIsEmpty();
            }
        }

        /// <summary>
        /// The last item.
        /// Raises an exception when the collection is empty.
        /// </summary>
        /// <exception cref="CollectionIsEmpty">when the collection is empty.</exception>
        public T Last
        {
            get
            {
                if (count >= 1)
                    return arr[count - 1];
                else
                    throw new CollectionIsEmpty();
            }
        }


        /// <summary>
        /// Origin index (index of the first item).
        /// </summary>
        /// <remarks>
        /// Accessible even if the collection is empty.
        /// </remarks>
        /// <seealso cref="RRandomList{T}.LastIndex"/>
        public int FirstIndex
        {
            get { return firstIndex; }
        }

        /// <summary>
        /// Index of the last item.
        /// </summary>
        /// <remarks>
        /// If the collection is empty, it is a value that less than the <see cref="FirstIndex"/>.
        /// </remarks>
        /// <seealso cref="RRandomList{T}.FirstIndex"/>
        public int LastIndex
        {
            get { return firstIndex + count - 1; }
        }


        /// <summary>
        /// Represents a quick indexed access to the specified item.
        /// </summary>
        /// <remarks>
        /// The given index must be in [ FirstIndex .. LastIndex ] inclusively.
        /// </remarks>
        /// <exception cref="CollectionIsEmpty">when the collection is empty.</exception>
        /// <exception cref="IndexOutOfBoundsException">when index is incorrect.</exception>
        /// <seealso cref="RRandomList{T}.FirstIndex"/>
        /// <seealso cref="RRandomList{T}.LastIndex"/>
        public T this[int index]
        {
            get
            {
                if (count == 0)
                    throw new CollectionIsEmpty();

                int localIndex = index - firstIndex;

                if (0 <= localIndex && localIndex < count)
                    return arr[localIndex];
                else
                    throw new IndexOutOfBoundsException(index, FirstIndex, LastIndex);
            }
        }




    }
}